/*jslint laxbreak: true, fragment: true */
/*
 Y E T . A N O T H E R . W E A T H E R . P L U G I N - 0.1
 License        : MIT
 Developers     : Wes Holliman - wes.holliman(at)gmail(dot)com 
                  Alex Nolasco - alex.nolasco(at)gmail(dot)com                                       
 Last Update    : June 14th, 2010
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
*/

(function($){
	$.fn.yaywp = function(options){
		var defaults = {
          yahooWeatherUrl: 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%3D'
         ,locationCode: ''
         ,timeout: 5000	
         ,templateUrl: ''
         ,autoRetry: false
         ,templateBody:'<div class="yaywp"><h3>${conditions}</h3><h3>${temperature}&#176;</h3><span>High: ${temperature_high}&#176; Low: ${temperature_low}&#176;</span></div>'
         ,onError: function(){}
         ,onSuccess: function(){}
		};
		options = $.extend(defaults, options);			
		
		// This plugin requires jsonp
		if(!$.jsonp){
			options.onError.call(this, 'this plugin requires jquery.jsonp 1.1.0 (c)2009 by Julian Aubourg');		
			return;
		}
		if(!$.template){
			options.onError.call(this, 'this plugin requires jquery.template 1.1.0 (c)2009 by Stan Lemon');		
			return;				
		}		
		if(options.locationCode===''){
			options.onError.call(this, 'The location code was not provided');		
			return;						
		}
		// return the jquery object to allow for chainability
		return this.each( function(){
			// 'this' is a DOM element
      // wrap 'this' in a jQuery object 
			var $this = $(this);
			
			if(options.templateUrl!==''){
				$.ajax({
					 url: options.templateUrl
					,cache: false
					,success: function(data){
						options.templateBody = data;
						loadYahooData($this, data, options);
					}
					,error:function(){
						options.onError.call(this, 'Error loading template ' + options.templateUrl, $this);
					}
				});
			} else if (options.templateBody!=='') {
        loadYahooData($this, options.templateBody, options);
			} else {
        options.onError.call(this, 'Error loading template ' + options.templateUrl, $this);
			}
		});
	};	
	
	/*
	* private
	*/
	function loadYahooData(elj, data, options){
		var weatherUrl = options.yahooWeatherUrl + '\'' + options.locationCode + '\'';
	
		$.jsonp({
			 url: weatherUrl
			,data:{'format':'json'}
			,dataType: 'jsonp'
			,callbackParameter: 'callback'
			,timeout: options.timeout
			,success: function(data, textStatus){
				draw(elj, data, options);
			}			
			,error:function(xhr, textStatus, errorThrown){      
				if(textStatus==='timeOut' && options.autoRetry===true){
					loadYahooData(elj, data, options); // repeat
				} else {          
					options.onError.call(this, textStatus, elj);
				}
			}
		});
	}
	
	/*
	* private
	*/	
	function draw(elj, data, options){
		if(typeof data.error !== 'undefined'){
			options.onError.call(this, data.error, elj);
			return;
		}
		
		var weather = data.query.results.channel;
		if(weather.description === 'Yahoo! Weather Error'){
			options.onError.call(this, weather.description, elj);
			return;					
		}
		
		var  t = $.template(options.templateBody)
			,localTime = matchTime(weather.item.title)
			,sunrise = matchTime(weather.astronomy.sunrise)
			,sunset = matchTime(weather.astronomy.sunset);
			
		elj.append(t,{
				 current_time: weather.item.title
				,conditions: weather.item.condition.text
				,feels_like: weather.wind.chill
				,pressure: weather.atmosphere.pressure
				,pressure_units: weather.units.pressure
				,humidity: weather.atmosphere.humidity
				,visibility: weather.atmosphere.visibility
				,visibility_units: weather.units.distance
				,dewpoint: 0
				,wind_dir: ConvertDegToDir(weather.wind.direction)
				,wind_speed: weather.wind.speed
				,wind_units: weather.units.speed
				,sunrise: weather.astronomy.sunrise
				,sunset: weather.astronomy.sunset
				,temperature: weather.item.condition.temp
				,temperature_high: weather.item.forecast[0].high
				,temperature_low: weather.item.forecast[0].low
				,condition_code: weather.item.condition.code
				,day_night: localTime >= sunrise && localTime <= sunset ? 'd' : 'n'
				,local_time: localTime
		});
		options.onSuccess.call(this, elj[0]);		
	}
	
	/*
	* private
	*/
	function ConvertDegToDir(deg) {
		var dir = '';	
		switch (true){
			case deg >= 1 && deg <= 11:
				dir = 'N';
				break;				
			case deg >= 12 && deg <= 32:
				dir = 'NNE';
				break;
			case deg >= 33 && deg <= 55:
				dir = 'NE';
				break;
			case deg >= 56 && deg <= 78:
				dir = 'ENE';
				break;				
			case deg >= 79 && deg <= 101:
				dir = 'E';
				break;				
			case deg >= 102 && deg <= 123:
				dir = 'ESE';
				break;				
			case deg >= 124 && deg <= 146:
				dir = 'SE';
				break;				
			case deg >= 147 && deg <= 168:
				dir = 'SSE';
				break;				
			case deg >= 169 && deg <= 191:
				dir = 'S';
				break;				
			case deg >= 192 && deg <= 214:
				dir = 'SSW';
				break;				
			case deg >= 215 && deg <= 236:
				dir = 'SW';
				break;				
			case deg >= 237 && deg <= 258:
				dir = 'WSW';
				break;				
			case deg >= 259 && deg <= 281:
				dir = 'W';
				break;				
			case deg >= 282 && deg <= 303:
				dir = 'WNW';
				break;				
			case deg >= 304 && deg <= 326:
				dir = 'NW';
				break;				
			case deg >= 327 && deg <= 349:
				dir = 'WNW';
				break;				
			case deg >= 350 && deg <= 360:
				dir = 'N';
				break;				
			default:
				dir = 'UNK';
				break;
		}	
		return dir;
	}
	/*
	* private
	*/	
	function matchTime(time) {
		var  re = /(\d{1,2}):(\d{2})\s(am|pm){1}/
		    ,match = re.exec(time)
		    ,hour = parseInt(match[1], 10)
		    ,min = parseInt(match[2], 10)
		    ,ano = match[3];				
		if (ano === 'pm' && hour < 12){
			hour += 12;
	  } else if (ano === 'am' && hour === 12){
			hour = 0;		
	  }
		var val = new Date();
		val.setHours(hour, min);		
		return val;
	}
	
})(jQuery);